package com.ruoyi.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.exception.BizBusinessException;
import com.ruoyi.wms.dto.WmsLiveStockInfoDto;
import com.ruoyi.wms.entity.WmsInLog;
import com.ruoyi.wms.entity.WmsLiveStockInfo;
import com.ruoyi.wms.entity.WmsOutLog;
import com.ruoyi.wms.mapper.WmsLiveStockInfoMapper;
import com.ruoyi.wms.mapstruct.WmsInLogMapStructMapper;
import com.ruoyi.wms.mapstruct.WmsLiveStockInfoMapStructMapper;
import com.ruoyi.wms.mapstruct.WmsOutLogMapStructMapper;
import com.ruoyi.wms.service.IWmsInLogService;
import com.ruoyi.wms.service.IWmsLiveStockInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.wms.service.IWmsOutLogService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;

/**
 * <p>
 * 实时库存 服务实现类
 * </p>
 *
 * @author 张晓光
 * @since 2023-10-26
 */
@Slf4j
@Service
@AllArgsConstructor
public class WmsLiveStockInfoServiceImpl extends ServiceImpl<WmsLiveStockInfoMapper, WmsLiveStockInfo> implements IWmsLiveStockInfoService {

    private final IWmsInLogService iWmsInLogService;
    private final IWmsOutLogService iWmsOutLogService;
    private final WmsOutLogMapStructMapper wmsOutLogMapStructMapper;
    private final WmsInLogMapStructMapper wmsInLogMapStructMapper;
    private final WmsLiveStockInfoMapStructMapper wmsLiveStockInfoMapStructMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean inStock(WmsLiveStockInfoDto dto) {
        WmsInLog wmsInLog = wmsInLogMapStructMapper.stockDtoToWmsInLog(dto);
        // 记录入库日志
        iWmsInLogService.saveInfo(wmsInLog);
        // 保存实时库存
        WmsLiveStockInfo stockInfo = wmsLiveStockInfoMapStructMapper.dtoToWmsLiveStockInfo(dto);
        return saveOrUpdate(stockInfo);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean outStock(WmsLiveStockInfoDto dto) {

        List<WmsLiveStockInfo> liveStockInfoList = list(
                Wrappers.<WmsLiveStockInfo>lambdaQuery()
                        .eq(WmsLiveStockInfo::getProductCode,dto.getProductCode())
                        .eq(StrUtil.isNotEmpty(dto.getWarehouseCode()),WmsLiveStockInfo::getWarehouseCode,dto.getWarehouseCode())
                        .eq(StrUtil.isNotEmpty(dto.getContainerCode()),WmsLiveStockInfo::getContainerCode,dto.getContainerCode())
                        .eq(StrUtil.isNotEmpty(dto.getLocationCode()),WmsLiveStockInfo::getLocationCode,dto.getLocationCode())
                        .orderByAsc(WmsLiveStockInfo::getCreateDate)
        );
        if(liveStockInfoList.isEmpty()){
            throw new BizBusinessException("商品："+dto.getProductCode()+"在仓库【"+dto.getWarehouseCode()+"】-库位【"+dto.getLocationCode()+"】库存不存在，不能出库");
        }
        long total = liveStockInfoList.stream().mapToLong(item->item.getNum().longValue()).sum();

        if(total<dto.getNum().longValue()){
            throw new BizBusinessException("商品："+dto.getProductCode()+"在仓库【"+dto.getWarehouseCode()+"】-库位【"+dto.getLocationCode()+"】库存不满足，需求量【"+dto.getNum()+"】，库存量【"+total+"】");
        }
        BigDecimal needNum = new BigDecimal(total);
        for(WmsLiveStockInfo stockInfo:liveStockInfoList){
            if(needNum.compareTo(stockInfo.getNum())<=0){
                needNum = needNum.subtract(stockInfo.getNum());
                removeById(stockInfo.getId());
            }else{
                stockInfo.setNum(stockInfo.getNum().subtract(needNum));
                updateById(stockInfo);
                if(!updateById(stockInfo)){
                    throw new BizBusinessException("库存已变更，请刷新重试！");
                }
                break;
            }
        }
        WmsOutLog outLog = wmsOutLogMapStructMapper.stockDtoToLog(dto);
        // 记录出库日志
        iWmsOutLogService.saveInfo(outLog);
        return true;
    }
}
